//------------------------------------------------------------------------------
//  <copyright file="KukaLBR4NatvieTests.cpp" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//  </copyright>
//------------------------------------------------------------------------------

#include "stdafx.h"
#include "KukaLBR4NativeTests.h"
#include "MockFRIConnection.h"
#include "TestPokeFRIConnection.h"
#include "TestResultStringCommon.h"

#include <KukaLBR4PlusController.h>

/// <summary> Test exchange of register values using the <c>RegisterExchange</c> class. </summary>
void KukaLBR4NativeTests::RegisterExchangeTest()
{
	unsigned int numRegisters = 3;
	unsigned int pRegisterSizesInBytes[3] = {1*sizeof(double), 2*sizeof(double), 3*sizeof(double)};

	RegisterExchange<double> *pRegExg  = new RegisterExchange<double>(
		numRegisters,
		pRegisterSizesInBytes);

	ControllerStateMachineRegisters<double> *pSourceRegisters = new ControllerStateMachineRegisters<double>(
		numRegisters,
		pRegisterSizesInBytes);

	ControllerStateMachineRegisters<double> *pDestinationRegisters = new ControllerStateMachineRegisters<double>(
		numRegisters,
		pRegisterSizesInBytes);

	// set an inital configuration of the source register
	double **tempReg = pSourceRegisters->GetRegisters();

	KukaLBR4NativeTests::ConfigureRegistersWithDefaultValues(tempReg);

	bool exchangeOccured = pRegExg->Consume(pDestinationRegisters);
	// confirm that we get no values if we try to consume before first value is published
	KUKALBR4NATIVEASSERT(!exchangeOccured, "Test that exchange did not occur");

	// publish the source registers
	pRegExg->Publish(pSourceRegisters);

	// consume and confirm that we get the correct values
	exchangeOccured = pRegExg->Consume(pDestinationRegisters);

	KUKALBR4NATIVEASSERT(exchangeOccured, "Test exchange occured");
	KukaLBR4NativeTests::AssertRegistersDefaultValues(pDestinationRegisters->GetRegisters());

	// publish 10 sets of registers then confirm that when we consume we only get the last one published
	tempReg = pSourceRegisters->GetRegisters();
	for(unsigned int i = 0; i < 10; ++i)
	{
		tempReg[0][0] = i;
		pRegExg->Publish(pSourceRegisters);
	}

	// confirm that destination registers are uncorrupeted
	KukaLBR4NativeTests::AssertRegistersDefaultValues(pDestinationRegisters->GetRegisters());

	// consume the latest registers
	exchangeOccured = pRegExg->Consume(pDestinationRegisters);

	KUKALBR4NATIVEASSERT(9.0 == pDestinationRegisters->GetRegister(0)[0], "Test that register is set to last value published");

	// try to consume a second time, this should result in no data being available
	exchangeOccured = pRegExg->Consume(pDestinationRegisters);

	KUKALBR4NATIVEASSERT(!exchangeOccured, "Test that exchange did not occur");
}

/// <summary> Configure a set of registers with known values for testing. </summary>
/// <param name="ppRegisters">
/// Register to configure.  Assumption is that at least 3 registers
/// are allocated with lengths of at least 1, 2, and 3 respectively.
/// </param>
void KukaLBR4NativeTests::ConfigureRegistersWithDefaultValues(double **ppRegisters)
{
	KUKALBR4NATIVEASSERT(ppRegisters != NULL, "ppRegisters is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[0] != NULL, "ppRegisters[0] is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[1] != NULL, "ppRegisters[1] is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[2] != NULL, "ppRegisters[2] is not NULL");

	ppRegisters[0][0] = 0;

	ppRegisters[1][0] = 1;
	ppRegisters[1][1] = 2;

	ppRegisters[2][0] = 3;
	ppRegisters[2][1] = 4;
	ppRegisters[2][2] = 5;
}

/// <summary> Asserts that a set of registers have the default values </summary>
/// <param name="ppRegisters">
/// Registers to confirm values of.  Assumption is that at least 3 registers
/// are allocated with length of at least 1, 2, and 3 respectively.
/// </param>
void KukaLBR4NativeTests::AssertRegistersDefaultValues(double **ppRegisters)
{
	KUKALBR4NATIVEASSERT(ppRegisters != NULL, "ppRegisters is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[0] != NULL, "ppRegisters[0] is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[1] != NULL, "ppRegisters[1] is not NULL");
	KUKALBR4NATIVEASSERT(ppRegisters[2] != NULL, "ppRegisters[2] is not NULL");

	KUKALBR4NATIVEASSERT(0.0 == ppRegisters[0][0], "Test registers are default values");

	KUKALBR4NATIVEASSERT(1.0 == ppRegisters[1][0], "Test registers are default values");
	KUKALBR4NATIVEASSERT(2.0 == ppRegisters[1][1], "Test registers are default values");

	KUKALBR4NATIVEASSERT(3.0 == ppRegisters[2][0], "Test registers are default values");
	KUKALBR4NATIVEASSERT(4.0 == ppRegisters[2][1], "Test registers are default values");
	KUKALBR4NATIVEASSERT(5.0 == ppRegisters[2][2], "Test registers are default values");
}

/// <summary> Generates a controller state machine for tests. </summary>
ControllerStateMachineDescription KukaLBR4NativeTests::GenerateCsmd1()
{
	ControllerStateMachineDescription csmd;

	csmd.NumStates = 2;

	csmd.State0.ControlMode = ControlModes::NoneControlMode;
	csmd.State0.Operations.NumOperations = 0;
	csmd.State0.NumTransitions = 1;
	csmd.State0.Transition0.NumTestOperands = 2;
	csmd.State0.Transition0.TestOpCode = KukaLBR4Operations::IsAnyElementGreaterThanVec6Op;
	csmd.State0.Transition0.TestOperand0.RegisterNumber = KukaLBR4PlusFeedbackRegisters::EstimatedTCPForceTorqueRegister;
	csmd.State0.Transition0.TestOperand0.RegisterType = RegisterTypes::Feedback;
	csmd.State0.Transition0.TestOperand1.RegisterNumber = KukaLBR4PlusWorkingRegisters::CartVec1Register;
	csmd.State0.Transition0.TestOperand1.RegisterType = RegisterTypes::Working;
	csmd.State0.Transition0.TargetState = 1;

	csmd.State1.ControlMode = ControlModes::NoneControlMode;
	csmd.State1.NumTransitions = 0;
	csmd.State1.Operations.NumOperations = 0;

	return csmd;
}

/// <summary>
/// Generate a csmd that executes a poke -- i.e. does position control until it encounters
/// a force in the environment along it's TCP's Z axis, then stops.
/// </summary>
ControllerStateMachineDescription KukaLBR4NativeTests::GeneratePokeCsmd()
{
	ControllerStateMachineDescription csmd;

	csmd.NumStates = 2;

	csmd.State0.ControlMode = ControlModes::JointPositionControlMode;
	csmd.State0.Operations.NumOperations = 0;
	csmd.State0.NumTransitions = 1;
	csmd.State0.Transition0.NumTestOperands = 2;
	csmd.State0.Transition0.TestOpCode = KukaLBR4Operations::IsAnyElementGreaterThanVec6Op;
	csmd.State0.Transition0.TestOperand0.RegisterNumber = KukaLBR4PlusFeedbackRegisters::EstimatedTCPForceTorqueRegister;
	csmd.State0.Transition0.TestOperand0.RegisterType = RegisterTypes::Feedback;
	csmd.State0.Transition0.TestOperand1.RegisterNumber = KukaLBR4PlusWorkingRegisters::CartVec1Register;
	csmd.State0.Transition0.TestOperand1.RegisterType = RegisterTypes::Working;
	csmd.State0.Transition0.TargetState = 1;

	csmd.State1.ControlMode = ControlModes::NoneControlMode;
	csmd.State1.NumTransitions = 0;
	csmd.State1.Operations.NumOperations = 0;

	return csmd;
}

/// <summary>
/// Generate a sequence of messages to IO thread that constantly reset the controller
/// state machine description.
/// <summary>
/// <param name="message"> Pointer to the <c>MessageDescription</c> struct to initialize. </param>
/// <param name="maxParameterSize"> Size of the parameter buffer allocated for <c>message->parameters</c>. </param>
void KukaLBR4NativeTests::SendTestSettingCsmdMessages(ControllerClientMessageHandler *pMsgHandler)
{
	unsigned int messageParameterBufferLength = max(sizeof(ControllerStateMachineDescription), sizeof(KukaLBR4PlusWorkingRegisters));
	unsigned int resonseParameterBufferLength = sizeof(KukaFeedbackMessage);
	MessageDescription *pMessage = new MessageDescription(messageParameterBufferLength);
	MessageDescription *pResponse = new MessageDescription(resonseParameterBufferLength);

	ControllerStateMachineDescription csmd = GenerateCsmd1();

	if(pMessage->ParameterBufferLength < sizeof(ControllerStateMachineDescription))
	{
		// default parameter buffer length should be able to accomodate all messages in use
		throw "Insufficient memory to allocate parameters";
	}

	pMessage->MessageType = MessageTypes::SetCsmdMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = sizeof(ControllerStateMachineDescription);

	memcpy_s(
		pMessage->pParameters,
		pMessage->ParameterBufferLength,
		&csmd,
		sizeof(ControllerStateMachineDescription));

	for(unsigned int iterationCount = 0; iterationCount < 1000; ++iterationCount)
	{

		pMessage->SequenceNumber = iterationCount;
		pMsgHandler->ProcessMessage(pMessage, pResponse);

		// make sure sequence number is correct
		KUKALBR4NATIVEASSERT(iterationCount == pResponse->SequenceNumber, "Iteration count is correct");

		// make sure success is indicated
		KUKALBR4NATIVEASSERT(1 == (int)pResponse->pParameters[0], "Parameters indicate success");
	}

	pMessage->MessageType = MessageTypes::ConnectionClosedMessageType;
	pMessage->ParameterLength = 0;
	pMessage->pParameters = NULL;

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	delete pMessage;
	delete pResponse;
}

/// <summary>
/// Send a sequence of messages to the ControllerClientMessageHandler
/// corresponding to a "poke" action, and check that proper feedback is received.
/// </summary>
/// <param name="pMsgHandler"> The ControllerclientMessagehandler to interact with. </param>
/// <param name="pFRIConnection"> The mock FRI connection that pMsgHandler was initialized with. </param>
void KukaLBR4NativeTests::SendPokeTestMessages(ControllerClientMessageHandler *pMsgHandler, TestPokeFRIConnection *pFRIConnection)
{
	unsigned int messageParameterBufferLength = max(sizeof(ControllerStateMachineDescription), sizeof(KukaLBR4PlusWorkingRegisters));
	unsigned int resonseParameterBufferLength = sizeof(KukaFeedbackMessage);
	MessageDescription *pMessage = new MessageDescription(messageParameterBufferLength);
	MessageDescription *pResponse = new MessageDescription(resonseParameterBufferLength);

	// send the csmd
	KUKALBR4NATIVEASSERT(!(pMessage->ParameterBufferLength < sizeof(ControllerStateMachineDescription)), "ParameterBufferLength is of sufficient size");
	pMessage->MessageType = MessageTypes::SetCsmdMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = sizeof(ControllerStateMachineDescription);

	ControllerStateMachineDescription csmd = GeneratePokeCsmd();
	memcpy_s(
		pMessage->pParameters,
		pMessage->ParameterBufferLength,
		&csmd,
		sizeof(ControllerStateMachineDescription));

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	KUKALBR4NATIVEASSERT(pResponse->MessageType == MessageTypes::SetCsmdMessageType, "Message type is SetCsmdMessageType");
	KUKALBR4NATIVEASSERT(pResponse->ParameterLength == (unsigned int)1, "Parameter length is one");
	KUKALBR4NATIVEASSERT(pResponse->pParameters[0] == 1, "Parameters indicate success");

	// set the target position register
	KUKALBR4NATIVEASSERT(!(pMessage->ParameterBufferLength < sizeof(KukaWorkingRegisterMessage)), "ParameterBufferLength is of sufficient size");
	pMessage->MessageType = MessageTypes::SetWorkingRegistersMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = sizeof(KukaWorkingRegisterMessage);

	KukaWorkingRegisterMessage payload;

	for (int i = 0; i<NUM_JOINTS; ++i)
	{
		payload.JointDampingCommandRegister[i] = 0;
		payload.JointPositionCommandRegister[i] = pPokeJointAngleTarget[i]; 
	}

	for (int i = 0; i<CARTESIAN_DIM; ++i)
	{
		payload.CartesianDampingCommandRegister[i] = 0;
		payload.CartesianStiffnessCommandRegister[i] = 0;
		payload.CartVec1Register[i] = 0;
		payload.CartVec2Register[i] = 0;
		payload.CartVec3Register[i] = 0;
	}

	for (int i = 0; i<CARTESIAN_FRAME_LENGTH; ++i)
	{
		payload.CartesianPositionCommandRegister[i] = 0;
		payload.Frame1Register[i] = 0;
	}

	memcpy_s(
		pMessage->pParameters,
		pMessage->ParameterBufferLength,
		&payload,
		sizeof(KukaWorkingRegisterMessage));

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	KUKALBR4NATIVEASSERT(pResponse->MessageType == MessageTypes::SetWorkingRegistersMessageType, "Message type is SetWorkingRegistersMessageType");
	KUKALBR4NATIVEASSERT(pResponse->ParameterLength == (unsigned int) 1, "Parameter length is 1");
	KUKALBR4NATIVEASSERT(pResponse->pParameters[0] == 1, "Parameters indicate success");

	// start the controller
	pMessage->MessageType = MessageTypes::StartCsmdMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = 0;

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	KUKALBR4NATIVEASSERT(pResponse->MessageType == MessageTypes::StartCsmdMessageType, "Message type is StartCsmdMessage Type");
	KUKALBR4NATIVEASSERT(pResponse->ParameterLength == (unsigned int) 1, "Parameter length is 1");
	KUKALBR4NATIVEASSERT(pResponse->pParameters[0] == 1, "Paramters indicate success");


	// request feedback
	Sleep(500);  // make sure controller thread has ample time to run before getting response
	pMessage->MessageType = MessageTypes::GetFeedbackMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = 0;

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	KUKALBR4NATIVEASSERT(!(pResponse->ParameterBufferLength < sizeof(KukaFeedbackMessage)), "ParamterBufferLength is of sufficient size");
	KUKALBR4NATIVEASSERT(pResponse->MessageType == MessageTypes::GetFeedbackMessageType, "Message type is GetFeedbackMessageType");

	// if this assertion fails, then likely IO thread did not have any feedback available whe
	// the request was sent.  This could either indicate a bug, or a timing issue with the test.
	// Increasing the sleep time in case 4 of GetNextMessage may help if it is a test timing issue.
	KUKALBR4NATIVEASSERT(pResponse->ParameterLength == sizeof(KukaFeedbackMessage), "Parameter length is correct for KukaFeedbackMessage");

	KukaFeedbackMessage feedbackMessage;

	memcpy_s(
		&feedbackMessage,
		sizeof(KukaFeedbackMessage),
		pResponse->pParameters,
		pResponse->ParameterLength);

	// Make sure the state indicated in the feedback reflects the previous messages sent and the
	// expected behavior of the controller state description.
	for(int i = 0; i < NUM_JOINTS; ++i)
	{
		KUKALBR4NATIVEASSERT(
			pPokeJointAngleTarget[i] == feedbackMessage.JointPositionCommandRegister[i],
			"Test commanded position");
		KUKALBR4NATIVEASSERT(
			pPokeJointAngleTarget[i] == feedbackMessage.MeasuredJointPositionRegister[i],
			"Test measured position");
	}

	KUKALBR4NATIVEASSERT((int)ControlModes::JointPositionControlMode == (int)feedbackMessage.ControllerStrategyCommandRegister, "Control mode is JointPositionControlMode");

	double nonzeroTCPEstimatedTorque[CARTESIAN_DIM] = {0, 0, 0, 0, 1, 0};

	pFRIConnection->SetTCPEstimatedTorque(nonzeroTCPEstimatedTorque);

	// ensure controller thread has time to run
	Sleep(500);
	// get feedback again
	pMessage->MessageType = MessageTypes::GetFeedbackMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = 0;

	pMsgHandler->ProcessMessage(pMessage, pResponse);


	KUKALBR4NATIVEASSERT(!(pResponse->ParameterBufferLength < sizeof(KukaFeedbackMessage)), "ParameterBufferLength is of sufficient size");
	KUKALBR4NATIVEASSERT(pResponse->MessageType == MessageTypes::GetFeedbackMessageType, "Message type is GetFeedbackMessageType");

	// if this assertion fails, then likely IO thread did not have any feedback available whe
	// the request was sent.  This could either indicate a bug, or a timing issue with the test.
	// Increasing the sleep time in case 4 of GetNextMessage may help if it is a test timing issue.
	KUKALBR4NATIVEASSERT(pResponse->ParameterLength, sizeof(KukaFeedbackMessage));

	memcpy_s(
		&feedbackMessage,
		sizeof(KukaFeedbackMessage),
		pResponse->pParameters,
		pResponse->ParameterLength);

	// check that the non-zero torque reading caused the state machine to move out of position contol to "do nothing"
	KUKALBR4NATIVEASSERT((int)ControlModes::NoneControlMode == (int)feedbackMessage.ControllerStrategyCommandRegister, "Control mode is NoneControlMode");

	// close the connection
	pMessage->MessageType = MessageTypes::ConnectionClosedMessageType;
	pMessage->IsResponse = 0;
	pMessage->ParameterLength = 0;
	pMessage->pParameters = NULL;

	pMsgHandler->ProcessMessage(pMessage, pResponse);

	delete pMessage;
	delete pResponse;
}

/// <summary>  Just ensure that we don't wind up in the weeds if many CSMDs are sent rapidly </summary>
void KukaLBR4NativeTests::TestSettingCsmd()
{ 
	MockFRIConnection *pFriConnection = new MockFRIConnection();

	KukaLBR4PlusController *pController = new KukaLBR4PlusController();

	ControllerClientMessageHandler *pClientMessageHandler = pController->StartKukaLBR4PlusController(pFriConnection);

	SendTestSettingCsmdMessages(pClientMessageHandler);

	KUKALBR4NATIVEASSERT(pController->WaitForControllerExit(10000) != WAIT_TIMEOUT, "Controller thread did not timeout");

	delete pController;
}

/// <summary> Test that a hypotetical "poke" CSMD behaves as expected. </summary>
void KukaLBR4NativeTests::PokeTest()
{
	TestPokeFRIConnection *pFriConnection = new TestPokeFRIConnection();

	KukaLBR4PlusController *pController = new KukaLBR4PlusController();

	ControllerClientMessageHandler *pClientMessageHandler = pController->StartKukaLBR4PlusController(pFriConnection);

	SendPokeTestMessages(pClientMessageHandler, pFriConnection);

	KUKALBR4NATIVEASSERT(pController->WaitForControllerExit(10000) != WAIT_TIMEOUT, "Controller thread did not timeout");

	delete pController;
}

/// <summary>
/// Performs a sanity check that passing native tests actually passes.
/// If this fails it is likely a test infra issue.
/// </summary>
void KukaLBR4NativeTests::NativeTestSanityCheckPassing()
{
}

/// <summary>
/// Performs a sanity check that failing native tests actually fails.
/// If this fails it is likely a test infra issue.
/// </summary>
void KukaLBR4NativeTests::NativeTestSanityCheckFailing()
{
	throw pIntentionalFailString;
}

/// <summary> Test exchange of register values using the <c>RegisterExchange</c> class. </summary>
/// <param name="resultString"> buffer for a failure message or indication that test passed. </param>
/// <param name="buffersize"> length of <c>resultString</c> buffer. </param>
void RegisterExchangeTest(char *resultString, int bufferSize)
{
	try
	{
		KukaLBR4NativeTests::RegisterExchangeTest();
	}
	catch (const char *ex)
	{
		strcpy_s(resultString, bufferSize, ex);
		return;
	}

	strcpy_s(resultString, bufferSize, KukaLBR4NativeTests::pPassString);
}

/// <summary> Test that a hypotetical "poke" CSMD behaves as expected. </summary>
/// <param name="resultString"> buffer for a failure message or indication that test passed. </param>
/// <param name="buffersize"> length of <c>resultString</c> buffer. </param>
void PokeTest(char *resultString, int bufferSize)
{
	try
	{
		KukaLBR4NativeTests::PokeTest();
	}
	catch (const char *ex)
	{
		strcpy_s(resultString, bufferSize, ex);
		return;
	}

	strcpy_s(resultString, bufferSize, KukaLBR4NativeTests::pPassString);
}

/// <summary>  Just ensure that we don't wind up in the weeds if many CSMDs are sent rapidly </summary>
/// <param name="resultString"> buffer for a failure message or indication that test passed. </param>
/// <param name="buffersize"> length of <c>resultString</c> buffer. </param>
void TestSettingCsmd(char *resultString, int bufferSize)
{
	try
	{
		KukaLBR4NativeTests::TestSettingCsmd();
	}
	catch (const char *ex)
	{
		strcpy_s(resultString, bufferSize, ex);
		return;
	}

	strcpy_s(resultString, bufferSize, KukaLBR4NativeTests::pPassString);
}

/// <summary>
/// Performs a sanity check that passing native tests actually passes.
/// If this fails it is likely a test infra issue.
/// </summary>
/// <param name="resultString"> buffer for a failure message or indication that test passed. </param>
/// <param name="buffersize"> length of <c>resultString</c> buffer. </param>
void NativeSanityCheckPassing(char *resultString, int bufferSize)
{
	try
	{
		KukaLBR4NativeTests::NativeTestSanityCheckPassing();
	}
	catch (const char *ex)
	{
		strcpy_s(resultString, bufferSize, ex);
		return;
	}

	strcpy_s(resultString, bufferSize, KukaLBR4NativeTests::pPassString);
}

/// <summary>
/// Performs a sanity check that passing native tests actually fails.
/// If this fails it is likely a test infra issue.
/// </summary>
/// <param name="resultString"> buffer for a failure message or indication that test passed. </param>
/// <param name="buffersize"> length of <c>resultString</c> buffer. </param>
void NativeSanityCheckFailing(char *resultString, int bufferSize)
{
	try
	{
		KukaLBR4NativeTests::NativeTestSanityCheckFailing();
	}
	catch (const char *ex)
	{
		strcpy_s(resultString, bufferSize, ex);
		return;
	}

	strcpy_s(resultString, bufferSize, KukaLBR4NativeTests::pPassString);
}
